package com.douqu.game.core.entity.db;

import com.bean.core.buffer.ByteBuffer;
import com.douqu.game.core.config.card.*;
import com.douqu.game.core.config.common.CommonData;
import com.douqu.game.core.config.goods.AccessoryConfig;
import com.douqu.game.core.config.goods.EquipConfig;
import com.douqu.game.core.config.goods.PropConfig;
import com.douqu.game.core.config.sprite.SoldierConfig;
import com.douqu.game.core.e.E_Attribute;
import com.douqu.game.core.entity.Player;
import com.douqu.game.core.factory.ConstantFactory;
import com.douqu.game.core.factory.DataFactory;
import com.douqu.game.core.protobuf.SGCommonProto;
import com.douqu.game.core.util.LogUtils;

import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArrayList;

/**
 * @Author: Bean
 * @Description:
 * @Date: 2017-11-25 17:26
 */
public class CardDB extends DB {

	/**
	 * 总战力
	 */
	public int fc;

	/**
	 * 是否上阵
	 */
	public boolean battle;

	/**
	 * 装备列表 key : 装备位置
	 */
	private Map<Integer, EquipDB> equipMap = new LinkedHashMap<>();

	/**
	 * 饰品列表 key : 饰品类型
	 */
	private Map<Integer, AccessoryDB> accessoryMap = new ConcurrentHashMap<>();

	/**
	 * 已激活的宿命列表
	 */
	private List<Integer> activeFateList = new CopyOnWriteArrayList<>();

	/**
	 * 吃药列表
	 */
	/** 药水使用的改变值 <药水id， 数量> **/
	public Map<Integer, Integer> cardLiquidMap = new ConcurrentHashMap<>();

	/**
	 * 星级
	 */
	public int star;

	private LvDB lvDB;

	private Player player;

	/**
	 * 军团连锁的,只用在怪物身上,临时数据,不存数据库
	 */
	private int[] legionChainData;

	/**
	 * 战斗里面的支援参数ID
	 */
	private int supportParamId;
	/**
	 * 附加属性
	 */
	private CommonData[] extAttr;

	/**
	 * 战斗里面的占位索引
	 */
	private int index;

	public CardDB(Player player) {
		super(DataFactory.CARD_KEY);

		this.player = player;

		lvDB = new LvDB(this);
	}

	public CardDB(int id) {
		super(DataFactory.CARD_KEY, id);

		lvDB = new LvDB(this);

		CardLvConfig curConfig = DataFactory.getInstance().getGameObject(DataFactory.CARD_LV_KEY, lvDB.lv);
		if (curConfig != null) {
			int totalExp = curConfig.getTotalExp(getConfig().quality);
			lvDB.exp = lvDB.exp < totalExp ? totalExp : lvDB.exp;

			CardLvConfig nextConfig = DataFactory.getInstance().getGameObject(DataFactory.CARD_LV_KEY, lvDB.lv + 1);
			if (nextConfig != null) {
				int nextTotalExp = nextConfig.getTotalExp(getConfig().quality);
				lvDB.exp = lvDB.exp >= nextTotalExp ? totalExp : lvDB.exp;
			}
		}

		init();
	}

	public CardDB(int id, Player player) {
		this(id);

		this.player = player;
	}

	public CardDB(CardDB cardDB)
	{
		super(DataFactory.CARD_KEY, cardDB.id);

		lvDB = new LvDB(this);
		lvDB.lv = cardDB.lvDB.lv;
		lvDB.exp = cardDB.lvDB.exp;

		star = cardDB.star;
		player = cardDB.player;
		fc = cardDB.fc;
		battle = cardDB.battle;

		for(Map.Entry<Integer, EquipDB> entry : cardDB.getEquipMap().entrySet())
		{
			equipMap.put(entry.getKey(), new EquipDB(entry.getValue()));
		}

		for (Map.Entry<Integer, AccessoryDB> entry : cardDB.getAccessoryMap().entrySet())
		{
			accessoryMap.put(entry.getKey(), new AccessoryDB(entry.getValue()));
		}

		activeFateList.addAll(cardDB.getActiveFateList());

		for(Map.Entry<Integer, Integer> entry : cardDB.getCardLiquidMap().entrySet())
		{
			cardLiquidMap.put(entry.getKey(), entry.getValue());
		}
	}

//	public CardDB(SpriteSoldierTemp spriteSoldierTemp)
//	{
//		super(DataFactory.CARD_KEY, spriteSoldierTemp.getId());
//
//		star = spriteSoldierTemp.getStar();
//
//		lvDB = new LvDB(this);
//		lvDB.lv = spriteSoldierTemp.getLv();
//
//		for(Map.Entry<Integer, EquipTemp> entry : spriteSoldierTemp.getEquipMap().entrySet())
//		{
//			equipMap.put(entry.getKey(), new EquipDB(entry.getValue()));
//		}
//
//		for(Map.Entry<Integer, AccessoryTemp> entry : spriteSoldierTemp.getAccessoryMap().entrySet())
//		{
//			accessoryMap.put(entry.getKey(), new AccessoryDB(entry.getValue()));
//		}
//
//		activeFateList.addAll(spriteSoldierTemp.getFateList());
//	}

	@Override
	public void loadFrom(ByteBuffer buffer) {
		super.loadFrom(buffer);

		star = buffer.readShort();

		lvDB.loadFrom(buffer);

		int size = buffer.readByte();
		DB db = null;
		for (int i = 0; i < size; i++) {
			db = new EquipDB();
			db.loadFrom(buffer);
			equipMap.put(buffer.readByte(), (EquipDB) db);
		}

		size = buffer.readByte();
		for (int i = 0; i < size; i++) {
			db = new AccessoryDB();
			db.loadFrom(buffer);
			accessoryMap.put(buffer.readByte(), (AccessoryDB) db);
		}

		size = buffer.readByte();
		for (int i = 0; i < size; i++) {
			activeFateList.add(buffer.readInt());
		}

		// ++++++++++++
		size = buffer.readShort();
		for (int i = 0; i < size; i++) {
			cardLiquidMap.put(buffer.readInt(), buffer.readInt());
		}
		buffer.readBoolean();

		//这里计算战斗力是没有加上军团连锁的
		updateFC();
	}

	@Override
	public void writeTo(ByteBuffer buffer)
	{
		super.writeTo(buffer);

		buffer.writeShort(star);

		lvDB.writeTo(buffer);

		buffer.writeByte(equipMap.size());
		for(Map.Entry<Integer, EquipDB> entry : equipMap.entrySet())
		{
			entry.getValue().writeTo(buffer);
			buffer.writeByte(entry.getKey());
		}

		buffer.writeByte(accessoryMap.size());
		for(Map.Entry<Integer, AccessoryDB> entry : accessoryMap.entrySet())
		{
			entry.getValue().writeTo(buffer);
			buffer.writeByte(entry.getKey());
		}

		buffer.writeByte(activeFateList.size());
		for (int i = 0; i < activeFateList.size(); i++) {
			buffer.writeInt(activeFateList.get(i).intValue());
		}

		// ++++++++++++
		buffer.writeShort(cardLiquidMap.size());
		for(Map.Entry<Integer, Integer> entry : cardLiquidMap.entrySet())
		{
			buffer.writeInt(entry.getKey());
			buffer.writeInt(entry.getValue());
		}

		buffer.writeBoolean(false);
	}

	@Override
	public void reset() {
		equipMap.clear();
		accessoryMap.clear();
		activeFateList.clear();
		init();
		lvDB.reset();
		star = 0;
		cardLiquidMap.clear();
		updateFC();
	}

	public void init()
	{
		List<EquipConfig> equipList = DataFactory.getInstance().getDataList(DataFactory.EQUIP_KEY);
		for (EquipConfig equip : equipList) {
			if (equip.quality == 1) {
				equipMap.put(equip.type, new EquipDB(equip.id));
			}
		}
		CardConfig cardConfig = getConfig();
		AccessoryConfig accessory = null;
		for (Integer key : cardConfig.getSoldier().accessory) {
			accessory = DataFactory.getInstance().getGameObject(DataFactory.ACCESSORY_KEY, key);
			accessoryMap.put(accessory.type, new AccessoryDB(accessory.id));
		}

		updateFC();
	}

	/**
	 * 获取卡牌的品质
	 * 
	 * @return
	 */
	public int getQuality() {
		CardConfig cardConfig = getConfig();
		return cardConfig.quality;
	}

	/**
	 * 更新战力
	 * 
	 * @return
	 */
	public int updateFC()
	{
		//20180810 后面6个属性的乘系数由0.5修改为1
		fc = (int) (getAttribute(E_Attribute.HP.getCode()) * 0.05
				  + getAttribute(E_Attribute.ATK.getCode())
				  + getAttribute(E_Attribute.DEF.getCode())
				  + getAttribute(E_Attribute.CRI.getCode())
				  + getAttribute(E_Attribute.REC.getCode())
				  + getAttribute(E_Attribute.ADD.getCode())
				  + getAttribute(E_Attribute.EXD.getCode())
				  + getAttribute(E_Attribute.HIT.getCode())
				  + getAttribute(E_Attribute.EVA.getCode()));

//		LogUtils.warn("计算属性后的fc id -> " + id + "  fc:" + fc);
		if(star > 0)
		{
			CardStarConfig cardStarConfig = DataFactory.getInstance().getGameObject(DataFactory.CARD_STAR_KEY, star);
			fc += cardStarConfig == null ? 0 : cardStarConfig.getAddFC(getConfig().quality);

//			LogUtils.warn("加上星级加成后的fc id -> " + id + "  fc:" + fc);
		}

		return fc;
	}

	/**
	 * 卡牌是否培养过
	 * 
	 * @return
	 */
	public boolean hasTrain() {
		// 卡片升级
		if (getLv() > 1) {
			return true;
		}

		// 卡片升星
		if (star > 0) {
			return true;
		}

		// 装备升级和升阶
		for(EquipDB equipDB : equipMap.values())
		{
			if (equipDB.getLv() > 0 || equipDB.upCount > 0) {
				return true;
			}
		}

		// 饰品升级和升阶
		for(AccessoryDB accessoryDB : accessoryMap.values())
		{
			if (accessoryDB.isActivated || accessoryDB.getLv() > 0 || accessoryDB.upLv > 0) {
				return true;
			}
		}

		return false;
	}

	public void addExp(int value) {
		lvDB.addExp(value);
	}

	public void addStar(int value) {
		star += value;
		star = star < 0 ? 0 : star;
	}

	/**
	 * 获取属性加成
	 * 
	 * @param attrId
	 * @return
	 */
	public int getAttribute(int attrId)
	{
		CardConfig cardConfig = getConfig();



//		LogUtils.debug("英雄获取属性 -> id:" + id + " name:" + cardConfig.name + " 属性ID:" + attrId + "->等级:" + lvDB.lv + ",星级->" + star);

		SoldierConfig soldierConfig = cardConfig.getSoldier();
		int result = soldierConfig.getAttribute(attrId, lvDB.lv, 0);

//		LogUtils.debug("计算基础加成长值后属性:" + result);

		result += soldierConfig.getStarAttribute(attrId, star);

//		LogUtils.debug("星级计算后属性:" + result);

		result += getFatePlus(attrId);

//		LogUtils.debug("宿命计算后属性:" + result);

		result += getEquipPlus(attrId);

//		LogUtils.debug("装备计算后属性:" + result);

		result += getAccessoryPlus(attrId);

//		LogUtils.debug("饰品计算后属性:" + result);

		result += getLiquidPlus(attrId);

//		LogUtils.debug("吃药计算后属性:" + result);

		result += getChainPlus(attrId);

//		LogUtils.debug("连锁计算后属性:" + result);

		result += getExtAttr(attrId);

//		LogUtils.debug("附加计算后属性："+result)

		//todo 天赋所加属性。
		if (player != null)
		result += player.getTalentData().getCardTalentAttribute(attrId,soldierConfig.profession,soldierConfig.camp,result);


//		LogUtils.debug("最终属性值 -》 att:" + attrId + ",value:" + result + " player:" + player);

		return result;
	}


	/**
	 * 获取宿命加成
	 * @param attrId
	 * @return
	 */
	public int getFatePlus(int attrId)
	{
		int result = 0;
		CardFateConfig fate = null;
		for (Integer fateId : activeFateList)
		{
			fate = DataFactory.getInstance().getGameObject(DataFactory.CARD_FATE_KEY, fateId);
			result += fate.getAttribute(attrId);
		}
		return result;
	}

	/**
	 * 获取装备加成
	 * @param attrId
	 * @return
	 */
	public int getEquipPlus(int attrId)
	{
		int result = 0;
		for(EquipDB equipDB : equipMap.values())
		{
			result += equipDB.getAttribute(attrId);
		}
		return result;
	}

	/**
	 * 获取饰品加成
	 * @param attrId
	 * @return
	 */
	public int getAccessoryPlus(int attrId)
	{
		int result = 0;
		for(AccessoryDB accessoryDB : accessoryMap.values())
		{
			if (accessoryDB.isActivated) {
				result += accessoryDB.getAttribute(attrId);
			}
		}
		return result;
	}
	/**
	 * 获取吃药加成
	 * @param attrId
	 * @return
	 */
	public int getLiquidPlus(int attrId)
	{
		int result = 0;
		PropConfig propConfig;
		for(Map.Entry<Integer, Integer> entry : cardLiquidMap.entrySet())
		{
			propConfig = DataFactory.getInstance().getGameObject(DataFactory.PROP_KEY, entry.getKey());
			if (propConfig != null && propConfig.type == ConstantFactory.PROP_TYPE_LIQUID && propConfig.liquidData[0].type == attrId)
			{
				result += (propConfig.liquidData[0].id * entry.getValue());
			}
		}
		return result;
	}

	/**
	 * 获取连锁加成
	 * @param attrId
	 * @return
	 */
	public int getChainPlus(int attrId)
	{
		int result = 0;
		if ((attrId == E_Attribute.ATK.getCode() || attrId == E_Attribute.DEF.getCode() || attrId == E_Attribute.HP.getCode())) {
			LegionChainConfig legionChain;
			if (player != null) {
				for(Map.Entry<Integer, Integer> entry : player.getCardData().getLegionChinaMap().entrySet())
				{
					Integer index = entry.getValue() == null ? -1 : entry.getValue();
					if (index < 0) {
						continue;
					}
					legionChain = DataFactory.getInstance().getGameObject(DataFactory.LEGION_CHAIN_KEY, entry.getKey());
					if (legionChain != null) {
						result += legionChain.getAtt(attrId, index);
					} else {
						LogUtils.error(
								"连锁属性错误 map : " + player.getCardData().getLegionChinaMap() + ", key:" + entry.getKey());
					}
				}
//				LogUtils.debug("加上连锁后属性:" + result);
			} else if (legionChainData != null) {
				result += DataFactory.getInstance().getLegionChainValue(attrId, legionChainData);
//				LogUtils.debug("加上连锁后属性:" + result);
			}
		}
		return result;
	}

	public int getEquipLvCount(int equipLv) {
		int count = 0;
		for (Map.Entry<Integer, EquipDB> entry : equipMap.entrySet()) {
			if (entry.getValue().getLv() >= equipLv)
				count++;
		}
		return count;
	}

	public void addFate(int fateId) {
		activeFateList.add(fateId);

		updateFC();
	}

	public boolean isHaveFate(int fateId) {
		return activeFateList.contains(fateId);
	}

	/**
	 * 打NPC的时候设置怪物信息
	 * 
	 * @param monsterLv
	 */
	public void setMonsterData(int[] monsterLv) {
		lvDB.lv = monsterLv[0];
		star = monsterLv[1];

		for(EquipDB equipDB : equipMap.values()) {
			equipDB.setMonsterData(monsterLv);
		}

		for(AccessoryDB accessoryDB : accessoryMap.values()) {
			accessoryDB.setMonsterData(monsterLv);
		}

		legionChainData = Arrays.copyOfRange(monsterLv, 6, monsterLv.length);
	}

	public void setExtAttr(CommonData[] value)
	{
		this.extAttr = value;
	}

	/***************************************
	 * 药水
	 ****************************************/
	/**
	 * 获取药水使用量
	 * 
	 * @param propId
	 * @return
	 */
	public int getUseLiquidCount(int propId) {
		Integer count = cardLiquidMap.get(propId);
		return count == null ? 0 : count.intValue();
	}

	public Map<Integer, Integer> getCardLiquidMap() {
		return cardLiquidMap;
	}

	/**
	 * 增加药水使用量
	 * 
	 * @param propId
	 * @param count
	 * @return
	 */
	public int addLiquidUseCount(int propId, int count) {
		Integer totalCount = cardLiquidMap.get(propId);
		totalCount = (totalCount == null ? 0 : totalCount.intValue()) + count;
		cardLiquidMap.put(propId, totalCount);
		return totalCount;
	}

	/**
	 * 药水使用是否达到了最大值
	 * 
	 * @param propId
	 * @param count
	 * @return
	 */
	public boolean isUseLiquidTouchMax(int propId, int count) {
		int totalCount = getUseLiquidCount(propId);
		totalCount += count;
		CardLvConfig cardLvConfig = DataFactory.getInstance().getGameObject(DataFactory.CARD_LV_KEY, getLv());
		Integer max = cardLvConfig.useLiquidMaxCount.get(propId);
		max = max == null ? 0 : max.intValue();
		if (totalCount > max) {
			return true;
		}
		return false;
	}

	/**
	 * 获取吃药的prop
	 * 
	 * @return
	 */
	public List<SGCommonProto.CommonObject> getUseLiquidProp()
	{
		List<SGCommonProto.CommonObject> list = new ArrayList<>();
		for(Map.Entry<Integer, Integer> entry : cardLiquidMap.entrySet())
		{
			list.add(SGCommonProto.CommonObject.newBuilder().setId(entry.getKey()).setValue(entry.getValue()).build());
		}
		return list;
	}

	/**
	 * 获取附加属性
	 * @param attrId
	 * @return
	 */
	public int getExtAttr(int attrId)
	{
		if(extAttr == null)
			return 0;

		int result = 0;
		for(CommonData commonData : extAttr)
		{
			if(commonData.id == attrId)
				result += commonData.value;
		}
		return result;
	}



	public int getLv() {
		return lvDB.lv;
	}

	public int getExp() {
		return lvDB.exp;
	}

	public EquipDB getEquipDB(int type) {
		return equipMap.get(type);
	}

	public AccessoryDB getAccessoryDB(int type) {
		return accessoryMap.get(type);
	}

	public Map<Integer, EquipDB> getEquipMap() {
		return equipMap;
	}

	public Map<Integer, AccessoryDB> getAccessoryMap() {
		return accessoryMap;
	}

	public List<Integer> getActiveFateList() {
		return activeFateList;
	}

	public int getSupportParamId() {
		return supportParamId;
	}

	public void setSupportParamId(int supportParamId) {
		this.supportParamId = supportParamId;
	}

	public int getIndex() {
		return index;
	}

	public void setIndex(int index) {
		this.index = index;
	}

	@Override
	public CardConfig getConfig() {
		return (CardConfig) super.getConfig();
	}

	@Override
	public String toString() {
		return "{" + "id=" + id + ", name=" + (getConfig() == null ? "" : getConfig().name) + ", lv=" + lvDB.lv + "} ";
	}
}
